热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

感应|都会_Glide源码分析

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Glide源码分析相关的知识,希望对你有一定的参考价值。前言:Glide作为

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Glide 源码分析相关的知识,希望对你有一定的参考价值。


前言:

Glide 作为android 图片加载领域最火的一款框架,其背后的源码设计同样精彩,今天就来一探究竟(基于Glide4.11.0版本)。

由于Glide框架的源码非常庞大,我们不会把所有细节分析一遍,本文只分析其核心源码,重点分析其对生命周期的监听和缓存的处理。

目录

一、with

二、load

三、into



我们的分析思路就从最简单的

Glide.with(context).load(url).into(imageView)

开始,来看看其背后的源码到底是怎么样的。


一、with

Glide有6个with的重载方法,返回值都是RequestManager

这6个方法其实可以分为两类:


  • 在主线程调用并且传入 Activity、Fragment或者View类型的Context(这种情况Glide会默认创建一个空的Fragment来感应当前Activity的生命周期)
  • 在子线程调用或者传入的Context是ApplicationContext(只要在子线程调用,无论传入什么都会装换为ApplicationContext)

下面我们通过看源码来验证:

我们看with(Activity)的情况

@NonNull
public static RequestManager with(@NonNull Activity activity)
return getRetriever(activity).get(activity);

其中 getRetriever返回了一个 RequestManagerRetriever 对象

@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context)
Preconditions.checkNotNull(context, "You cannot start a load on a not yet attached View or a Fragment where getActivity() returns null (which usually occurs when getActivity() is called before the Fragment is attached or after the Fragment is destroyed).");
return get(context).getRequestManagerRetriever();

我们来看其get方法:

 看,虽然传入的是Activity,但是如果不是主线程就转换为ApplicationContext来处理,这样就和with(Application)是一样的,我们先来看这条分支:

继续跟进:

@NonNull
private RequestManager getApplicationManager(@NonNull Context context)
if (this.applicationManager == null)
synchronized(this)
if (this.applicationManager == null)
Glide glide = Glide.get(context.getApplicationContext());
this.applicationManager = this.factory.build(glide,
new ApplicationLifecycle(),
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());



return this.applicationManager;

 比较直接,通过工厂模式创建一个 RequestManager 对象返回就结束了。

然后我们重点来看第二条分支的情况(主线程+Activity、Fragment、或者View)

跟进到fragmentGet,通过方法名可以看出,这里面会构造一个Fragment

/** @deprecated */
@Deprecated
@NonNull
private RequestManager fragmentGet(@NonNull Context context, @NonNull FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible)
//重点代码,这里会创建出RequestManagerFragment
RequestManagerFragment current = this.getRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null)
Glide glide = Glide.get(context);
requestManager = this.factory.build(glide, current.getGlideLifecycle(),
current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);

return requestManager;

 继续跟进fragmentGet方法的第一行代码:

this.getRequestManagerFragment(fm, parentHint, isParentVisible);

package com.bumptech.glide.manager;
public class RequestManagerRetriever implements Callback
...
@NonNull
private RequestManagerFragment getRequestManagerFragment(@NonNull FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible)
//第一步 先通过Tag找下当前是否已经有构造好的Fragment
RequestManagerFragment current = (RequestManagerFragment)fm.findFragmentByTag("com.bumptech.glide.manager");
if (current == null)
//第二步 如果第一步找不到 在从缓存里找下
current = (RequestManagerFragment)this.pendingRequestManagerFragments.get(fm);
if (current == null)
//第三步 缓存里也没有 就创建一个
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible)
current.getGlideLifecycle().onStart();

//放入缓存 避免重复创建,此时再调用此方法就能从缓存直接拿到了
this.pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, "com.bumptech.glide.manager").commitAllowingStateLoss();

//发handler去移除缓存里的fragment,当此handler消息被执行时,通过
//fm.findFragmentByTag已经可以获取到当前fragment了
//注意,这里必须是发handler 不能直接从缓存移除
//因为fragment的加载也是通过handler消息来驱动的,这里牵扯到handler消息机制的原理,简单理解就是handler消息是排队被处理的,下面发的handler消息排在处理fragment消息的后面
this.handler.obtainMessage(1, fm).sendToTarget();


return current;

注释里写的比较清楚了,先通过fm.findFragmentByTag来获取,没有就从缓存取,在没有就创建出RequestManagerFragment。

这里面有个细节就是作者设计了一个缓存pendingRequestManagerFragments(就是一个Map)来防止fragment重复创建,其中从缓存中移除fragment的时机涉及到了fragment的加载原理(handler驱动),和handler机制的原理,如果对二者不熟悉,可能不太容易理解。
注释里面我也给出了详细的解释,如还不能理解请先看下Fragment、Handler相关源码。

现在Fragment有了,那是如何做到感应当前Activity生命周期的呢?

我们来看下RequestManagerFragment的源码:



二、load

三、into

推荐阅读
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • Html5-Canvas实现简易的抽奖转盘效果
    本文介绍了如何使用Html5和Canvas标签来实现简易的抽奖转盘效果,同时使用了jQueryRotate.js旋转插件。文章中给出了主要的html和css代码,并展示了实现的基本效果。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 树莓派语音控制的配置方法和步骤
    本文介绍了在树莓派上实现语音控制的配置方法和步骤。首先感谢博主Eoman的帮助,文章参考了他的内容。树莓派的配置需要通过sudo raspi-config进行,然后使用Eoman的控制方法,即安装wiringPi库并编写控制引脚的脚本。具体的安装步骤和脚本编写方法在文章中详细介绍。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • VueCLI多页分目录打包的步骤记录
    本文介绍了使用VueCLI进行多页分目录打包的步骤,包括页面目录结构、安装依赖、获取Vue CLI需要的多页对象等内容。同时还提供了自定义不同模块页面标题的方法。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
author-avatar
齐鲁墨_931
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有